
static struct hrtimer_clock_base *__next_base(struct hrtimer_cpu_base *cpu_base, unsigned int *active)
{
    unsigned int idx;

    if (!*active)
        return NULL;

    idx = __ffs(*active);
    *active &= ~(1U << idx);

    return &cpu_base->clock_base[idx];
}

static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base,
                                         const struct hrtimer *exclude,
                                         unsigned int active,
                                         ktime_t expires_next)
{
    struct hrtimer_clock_base *base;
    ktime_t expires;

    for_each_active_base(base, cpu_base, active)
    {
        struct timerqueue_node *next;
        struct hrtimer *timer;

        next = timerqueue_getnext(&base->active);
        timer = container_of(next, struct hrtimer, node);
        if (timer == exclude)
        {
            /* Get to the next timer in the queue. */
            next = timerqueue_iterate_next(next);
            if (!next)
                continue;

            timer = container_of(next, struct hrtimer, node);
        }
        expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
        if (expires < expires_next)
        {
            expires_next = expires;

            /* Skip cpu_base update if a timer is being excluded. */
            if (exclude)
                continue;

            if (timer->is_soft)
                cpu_base->softirq_next_timer = timer;
            else
                cpu_base->next_timer = timer;
        }
    }
    /*
     * clock_was_set() might have changed base->offset of any of
     * the clock bases so the result might be negative. Fix it up
     * to prevent a false positive in clockevents_program_event().
     */
    if (expires_next < 0)
        expires_next = 0;
    return expires_next;
}

/*
 * Recomputes cpu_base::*next_timer and returns the earliest expires_next
 * but does not set cpu_base::*expires_next, that is done by
 * hrtimer[_force]_reprogram and hrtimer_interrupt only. When updating
 * cpu_base::*expires_next right away, reprogramming logic would no longer
 * work.
 *
 * When a softirq is pending, we can ignore the HRTIMER_ACTIVE_SOFT bases,
 * those timers will get run whenever the softirq gets handled, at the end of
 * hrtimer_run_softirq(), hrtimer_update_softirq_timer() will re-add these bases.
 *
 * Therefore softirq values are those from the HRTIMER_ACTIVE_SOFT clock bases.
 * The !softirq values are the minima across HRTIMER_ACTIVE_ALL, unless an actual
 * softirq is pending, in which case they're the minima of HRTIMER_ACTIVE_HARD.
 *
 * @active_mask must be one of:
 *  - HRTIMER_ACTIVE_ALL,
 *  - HRTIMER_ACTIVE_SOFT, or
 *  - HRTIMER_ACTIVE_HARD.
 */
static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_mask)
{
    unsigned int active;
    struct hrtimer *next_timer = NULL;
    ktime_t expires_next = KTIME_MAX;

    if (!cpu_base->softirq_activated && (active_mask & HRTIMER_ACTIVE_SOFT))
    {
        active = cpu_base->active_bases & HRTIMER_ACTIVE_SOFT;
        cpu_base->softirq_next_timer = NULL;
        expires_next = __hrtimer_next_event_base(cpu_base, NULL,
                                                 active, KTIME_MAX);

        next_timer = cpu_base->softirq_next_timer;
    }

    if (active_mask & HRTIMER_ACTIVE_HARD)
    {
        active = cpu_base->active_bases & HRTIMER_ACTIVE_HARD;
        cpu_base->next_timer = next_timer;
        expires_next = __hrtimer_next_event_base(cpu_base, NULL, active,
                                                 expires_next);
    }

    return expires_next;
}

static ktime_t hrtimer_update_next_event(struct hrtimer_cpu_base *cpu_base)
{
    ktime_t expires_next, soft = KTIME_MAX;

    /*
     * If the soft interrupt has already been activated, ignore the
     * soft bases. They will be handled in the already raised soft
     * interrupt.
     */
    if (!cpu_base->softirq_activated)
    {
        soft = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_SOFT);
        /*
         * Update the soft expiry time. clock_settime() might have
         * affected it.
         */
        cpu_base->softirq_expires_next = soft;
    }

    expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_HARD);
    /*
     * If a softirq timer is expiring first, update cpu_base->next_timer
     * and program the hardware with the soft expiry time.
     */
    if (expires_next > soft)
    {
        cpu_base->next_timer = cpu_base->softirq_next_timer;
        expires_next = soft;
    }

    return expires_next;
}
